Named Return Values in C++

Contents|Index|Previous|Next
Named return values in C++

GNU C++ extends the function-definition syntax, which allows you to specify a name for the result of a function outside the body of the definition, in C++ programs.

    type
    functionname (args) return resultname;
    {
       ...
       body
       ...
    }

You can use this feature to avoid an extra constructor call when a function result has a class type. For example, consider a function, m, declared as ‘X v =m ();’, whose result is of class X.

    X
    m ()
    {
       X b;
       b.a = 23;
       return b;
    }

Although ‘m’ appears to have no arguments, in fact it has one implicit argument: the address of the return value. At invocation, the address of enough space to hold ‘v’ is sent in as the implicit argument. Then ‘b’ is constructed and its ‘a’ field is set to the value 23. Finally, a copy constructor (a constructor of the form ‘X(X&)’) is applied to ‘b’, with the (implicit) return value location as the target, so that ‘v’ is now bound to the return value.

But this is wasteful. The local ‘b’ is declared just to hold something that will be copied right out. While a compiler that combined an elision algorithm with interprocedural data flow analysis could conceivably eliminate all of this, it is much more practical to allow you to assist the compiler in generating efficient code by manipulating the return value explicitly, thus avoiding the local variable and copy constructor altogether.

Using the extended GNU C++ function-definition syntax, you can avoid the temporary allocation and copying by naming r as your return value at the outset, and assigning to its ‘a’ field directly, as in the following example.

    X
    m () return r;
    {
       r.a = 23;
    }

The declaration of ‘r’ is a standard, proper declaration, whose effects are executed before any of the body of ‘m’.

Functions of this type impose no additional restrictions; in particular, you can execute return statements, or return implicitly by reaching the end of the function body (falling off the edge). Cases like the following example (or even the statement, Xm () return r (23) ; { }) are unambiguous, since the return value ‘r’ has been initialized in either case.

    X
    m () return r (23);
    {
       return;
    }

The following code may be hard to read, but also works predictably:

    X
    m () return r;
    {
       X b;
       return b;
    }

The return value slot denoted by ‘r’ is initialized at the outset, but the statement ‘return b;’ overrides this value. The compiler deals with this by destroying ‘r’ (calling the destructor if there is one, or doing nothing if there is not), and then reinitializing ‘r’ with ‘b’.

This extension is provided primarily to help people who use overloaded operators, where there is a great need to control not just the arguments, but the return values of functions. For classes where the copy constructor incurs a heavy performance penalty (especially in the common case where there is a quick default constructor), this is a major savings. The disadvantage of this extension is that you do not control when the default constructor for the return value is called: it is always called at the beginning.

Top|Contents|Index|Previous|Next